
/* ========================================================================
	Project  Name			: Win32 Lightweight  Class Library Test
	Module Name				: Registry Class
	Create					: 1996-06-01(Sat)
	Update					: 2010-05-09(Sun)
	Copyright				: H.Shirouzu
	Reference				: 
	======================================================================== */
#include "tlib.h"
#ifdef _USE_T_INI_
static char *tini_id =
"@(#)Copyright (C) 1996-2010 H.Shirouzu		tini.cpp	Ver0.97";

#include <stdio.h>
#include <io.h>
#include <mbstring.h>
#include "tini.h"

TInifile::TInifile(const char *_ini_file)
{
	ini_file = NULL;
	root_sec = cur_sec = NULL;
	ini_size = -1;
	hMutex = NULL;
	if (_ini_file) Init(_ini_file);
}

TInifile::~TInifile(void)
{
	free(ini_file);
	if (hMutex) ::CloseHandle(hMutex);
}

BOOL TInifile::Strip(const char *s, char *d, const char *strip_chars, const char *quote_chars)
{
	const char	*sv_s = s;
	const char	*e = s + strlen(s);
	int			len;
	char		start_quote = quote_chars[0];
	char		end_quote   = quote_chars[1];

	if (!d) d = (char *)s;

	while (*s && strchr(strip_chars, *s)) s++;

	if (*s == start_quote) {
		s++;
		while (s <= e && *e != end_quote) e--;
		if (s > e) goto ERR;
	}
	else {
		e--;
		while (s <= e && strchr(strip_chars, *e)) e--;
		if (s > e) goto ERR;
		e++;
	}

	len = (int)(e - s);
	memmove(d, s, len);
	d[len] = 0;
	return	TRUE;

ERR:
	if (sv_s != d) strcpy(d, sv_s);
	return	FALSE;
}

BOOL TInifile::Parse(const char *buf, BOOL *is_section, char *name, char *val)
{
	const char	*p = buf;

	while (*p && strchr(" \t\r\n", *p)) p++;

	if (*p == '[') {
		if (!Strip(p, name, " \t\r\n", "[]")) return FALSE;
		*is_section = TRUE;
		return	TRUE;
	}

	*is_section = FALSE;

	if (!isalnum(*p)) return FALSE;

	const char *e = p;
	while (*e && *e != '=') e++;
	if (*e != '=') return FALSE;

	int	len = (int)(e - p);
	memcpy(name, p, len);
	name[len] = 0;

	if (!Strip(name)) return FALSE;

	strcpy(val, e+1);
	return	Strip(val);
}

BOOL TInifile::GetFileInfo(LPTSTR	fname, FILETIME *ft, int *size)
{
	WIN32_FIND_DATA	fdat;
	HANDLE	hFind = FindFirstFile(fname, &fdat);

	if (hFind == INVALID_HANDLE_VALUE) return FALSE;

	*ft   = fdat.ftLastWriteTime;
	*size = fdat.nFileSizeLow;

	FindClose(hFind);
	return	TRUE;
}
#ifdef _USE_T_CRYPT_
BOOL TInifile::Lock()
{
	if (!hMutex) {
		char	buf[1024];
		char	*key = (char *)_mbsrchr((u_char *)ini_file, '\\');

		key = key ? key+1 : ini_file;

		sprintf(buf, "%s_%x", key, MakeHash(ini_file, (int)strlen(ini_file), 0));

		if (!(hMutex = ::CreateMutexA(NULL, FALSE, buf))) return FALSE;
	}

	return	::WaitForSingleObject(hMutex, INFINITE);
}

void TInifile::UnLock()
{
	if (hMutex) ReleaseMutex(hMutex);
}

#endif

void TInifile::Init(const char *_ini_file)
{
	if (_ini_file) ini_file = strdup(_ini_file);

#ifdef _USE_T_CRYPT_
	Lock();
#endif
	FILE	*fp = fopen(ini_file, "r");

	AddObj(root_sec = new TIniSection());

	if (fp) {
#define MAX_INI_LINE	(64 * 1024)
		char	*buf = new char [MAX_INI_LINE];
		char	*val = new char [MAX_INI_LINE];
		char	name[1024];
		BOOL	is_section;

		TIniSection	*target_sec = root_sec;

		while (fgets(buf, MAX_INI_LINE, fp)) {
			BOOL	ret = Parse(buf, &is_section, name, val);

			if (!ret) {
				target_sec->AddKey(NULL, buf);
			}
			else if (is_section) {
				target_sec = new TIniSection();
				target_sec->Set(name);
				AddObj(target_sec);
			}
			else {
				target_sec->AddKey(name, val);
			}
		}
		delete [] val;
		delete [] buf;
		fclose(fp);
//		GetFileInfo(ini_file, &ini_ft, &ini_size);
	}
#ifdef _USE_T_CRYPT_
	UnLock();
#endif
}

void TInifile::UnInit()
{
	for (TIniSection *sec; (sec = (TIniSection *)TopObj()); ) {
		DelObj(sec);
		delete sec;
	}
	root_sec = NULL;
}

BOOL TInifile::WriteIni()
{
#ifdef _USE_T_CRYPT_
	Lock();
#endif

	BOOL	ret = FALSE;
	FILE	*fp = fopen(ini_file, "w");

	if (fp) {
		for (TIniSection *sec = (TIniSection *)TopObj(); sec; sec = (TIniSection *)NextObj(sec)) {
			TIniKey *key = (TIniKey *)sec->TopObj();
			if (key) {
				if (sec->Name()) {
					if (fprintf(fp, "[%s]\n", sec->Name()) < 0) goto END;
				}
				while (key) {
					if (key->Key())	{
						if (fprintf(fp, "%s=\"%s\"\n", key->Key(), key->Val()) < 0) goto END;
					}
					else {
						if (fprintf(fp, "%s", key->Val()) < 0) goto END;
					}
					key = (TIniKey *)sec->NextObj(key);
				}
			}
		}
		ret = TRUE;
END:
		fclose(fp);
	}
#ifdef _USE_T_CRYPT_
	UnLock();
#endif

	return	ret;
}

BOOL TInifile::StartUpdate()
{
/*	FILETIME	ft;
	int			size;

	if (GetFileInfo(ini_file, &ft, &size) && (CompareFileTime(&ft, &ini_ft) || size != ini_size)){
		UnInit();
		Init();
	}
*/	return	TRUE;
}

BOOL TInifile::EndUpdate()
{
	return	WriteIni();
}

TIniSection *TInifile::SearchSection(const char *section)
{
	for (TIniSection *sec = root_sec; sec; sec = (TIniSection *)NextObj(sec)) {
		if (sec->Name() && strcmpi(sec->Name(), section) == 0) return sec;
	}
	return	NULL;
}

void TInifile::SetSection(const char *section)
{
	if (cur_sec && cur_sec != root_sec && !cur_sec->TopObj()) {
		DelObj(cur_sec);
		delete cur_sec;
	}

	if ((cur_sec = SearchSection(section)) == NULL) {
		cur_sec = new TIniSection();
		cur_sec->Set(section);
		AddObj(cur_sec);
	}
}

BOOL TInifile::DelSection(const char *section)
{
	TIniSection *sec = SearchSection(section);

	if (!sec) return FALSE;

	DelObj(sec);
	delete sec;
	if (sec == cur_sec) cur_sec = NULL;
	return	TRUE;
}

BOOL TInifile::DelKey(const char *key)
{
	return	cur_sec ? cur_sec->DelKey(key) : FALSE;
}

BOOL TInifile::SetStr(const char *key, const char *val)
{
	if (!val) return DelKey(key);
	return	cur_sec ? cur_sec->AddKey(key, val) : FALSE;
}

DWORD TInifile::GetStr(const char *key_name, char *val, int max_size, const char *default_val)
{
	TIniKey *key = cur_sec ? cur_sec->SearchKey(key_name) : NULL;
	return	sprintf(val, "%.*s", max_size, key ? key->Val() : default_val);
}

BOOL TInifile::SetInt(const char *key, int val)
{
	char	buf[100];
	sprintf(buf, "%d", val);
	return	SetStr(key, buf);
}

BOOL TInifile::SetInt64(const char *key, __int64 val)
{
	char	buf[100];
	sprintf(buf, "%lld", val);
	return	SetStr(key, buf);
}

int TInifile::GetInt(const char *key, int default_val)
{
	char	buf[100];
	if (GetStr(key, buf, sizeof(buf), "") <= 0) return default_val;
	return	atoi(buf);
}

__int64 TInifile::GetInt64(const char *key, __int64 default_val)
{
	char	buf[100];
	if (GetStr(key, buf, sizeof(buf), "") <= 0) return default_val;
	return	_atoi64(buf);
}

#endif